package com.whfc.emp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.file.properties.FileExpirationRules;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.FileUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.*;
import com.whfc.emp.entity.*;
import com.whfc.emp.param.AppPayrollAddParam;
import com.whfc.emp.param.AppPayrollDetailEditParam;
import com.whfc.emp.param.AppPayrollListParam;
import com.whfc.emp.service.AppPayrollService;
import com.whfc.entity.dto.OssPathDTO;
import com.whfc.fuum.service.SysDeptService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author guodong_sun
 * @Description: 人员工资
 * @date 2019年9月3日
 */
@DubboService(interfaceClass = AppPayrollService.class, version = "1.0.0", timeout = 5000)
public class AppPayrollServiceImpl implements AppPayrollService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppPayrollMapper appPayrollMapper;

    @Autowired
    private AppPayrollAttachMapper appPayrollAttachMapper;

    @Autowired
    private AppPayrollEmpMapper appPayrollEmpMapper;

    @Autowired
    private AppEmpGroupMapper appEmpGroupMapper;

    @Autowired
    private AppEmpDayMapper appEmpDayMapper;

    @Autowired
    private AppEmpBankMapper appEmpBankMapper;

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppPayrollEmpImgMapper appPayrollEmpImgMapper;

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private FilePathConfig msFilePathConfig;

    private static final String HEAD = "%s%s年%s月人员工资表";

    @Override
    public PageData<AppPayrollDTO> list(AppPayrollListParam request) {
        logger.info("查询人员工资列表，request：{}", request);
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<AppPayrollDTO> list = appPayrollMapper.selectByParam(request);
        PageHelper.clearPage();
        for (AppPayrollDTO appPayrollDTO : list) {
            Integer payrollId = appPayrollDTO.getPayrollId();
            Integer attachCnt = appPayrollAttachMapper.selectAttachNumByPayrollId(payrollId);
            appPayrollDTO.setAttachCnt(attachCnt);
        }
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public AppPayrollDetailDTO detail(Integer payrollId) {
        logger.info("查询人员工资详情，payrollId：{}", payrollId);
        AppPayrollDetailDTO result = new AppPayrollDetailDTO();
        //基本信息
        AppPayroll appPayroll = appPayrollMapper.selectByPrimaryKey(payrollId);
        BeanUtils.copyProperties(appPayroll, result);
        result.setPayrollId(payrollId);

        //附件信息
        List<AppPayrollAttachDTO> attachList = appPayrollAttachMapper.selectByPayrollId(payrollId);
        result.setAttachList(attachList);

        //人员信息
        List<AppPayrollEmpDTO> empList = appPayrollEmpMapper.selectByPayrollId(payrollId);
        //查找工资图片
        for (AppPayrollEmpDTO appPayrollEmpDTO : empList) {
            List<String> imgUrlList = appPayrollEmpImgMapper.selectImgUrlList(appPayrollEmpDTO.getId());
            appPayrollEmpDTO.setImgUrlList(imgUrlList);
        }
        result.setEmpList(empList);
        return result;
    }

    @Override
    public PageData<AppPayrollEmpDTO> empPayrollList(Integer payrollId, Integer pageNum, Integer pageSize) {
        logger.info("查询发放工资人员列表，payrollId：{},pageNum:{},pageSize:{}", payrollId, pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AppPayrollEmpDTO> list = appPayrollEmpMapper.selectByPayrollId(payrollId);
        PageHelper.clearPage();
        //查找工资图片
        for (AppPayrollEmpDTO appPayrollEmpDTO : list) {
            List<String> imgUrlList = appPayrollEmpImgMapper.selectImgUrlList(appPayrollEmpDTO.getId());
            appPayrollEmpDTO.setImgUrlList(imgUrlList);
        }
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public void add(AppPayrollAddParam request) {
        logger.info("添加工资记录，request：{}", request);
        Integer groupId = request.getGroupId();
        AppEmpGroup appEmpGroup = appEmpGroupMapper.selectByPrimaryKey(groupId);
        if (appEmpGroup == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该班组不存在");
        }
        Integer deptId = request.getDeptId();
        Integer year = request.getYear();
        Integer month = request.getMonth();
        Date date = DateUtil.parseDate(year + "-" + month, "yyyy-MM");
        Date monthBegin = DateUtil.getMonthBegin(date);
        Date monthEnd = DateUtil.getMonthEnd(date);

        // 查找该月份是否已经有工资记录
        Integer cnt = appPayrollMapper.countByDeptIdAndCorpId(deptId, groupId, year, month);
        if (cnt > 0) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该月份的工资记录已存在，不能重复添加");
        }

        //向app_payroll中插入数据
        AppPayroll appPayroll = new AppPayroll();
        BeanUtils.copyProperties(request, appPayroll);
        appPayroll.setCorpId(appEmpGroup.getCorpId());
        appPayroll.setCorpName(appEmpGroup.getCorpName());
        appPayrollMapper.insertSelective(appPayroll);
        Integer payrollId = appPayroll.getId();
        //根据groupId 和deptId 查找员工 和出勤天数
        List<Integer> empIdList = appEmpDayMapper.selectEmpIdByCorpIdAndDeptId(groupId, deptId, monthBegin, monthEnd);
        for (Integer empId : empIdList) {
            Integer workDays = appEmpDayMapper.selectAttendDaysByEmpId(deptId, empId, monthBegin, monthEnd);
            AppPayrollEmp record = new AppPayrollEmp();
            record.setAttendDays(workDays);
            record.setEmpId(empId);
            record.setPayrollId(payrollId);
            appPayrollEmpMapper.insertSelective(record);
        }
    }

    @Override
    public void edit(AppPayrollDetailEditParam request) {
        logger.info("添加工资记录，request：{}", JSONObject.toJSONString(request));
        AppPayrollEmp payrollEmp = appPayrollEmpMapper.selectPayrollEmp(request.getPayrollId(), request.getEmpId());
        if (payrollEmp == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "该人员记录不存在");
        }
        appPayrollEmpMapper.updateByPayrollIdAndEmpId(request);

        //删除旧的图片
        appPayrollEmpImgMapper.logicDel(payrollEmp.getId());

        //保存工资照片
        List<String> imgUrlList = request.getImgUrlList();
        if (imgUrlList == null || imgUrlList.isEmpty()) {
            return;
        }
        for (String imgUrl : imgUrlList) {
            AppPayrollEmpImg empImg = new AppPayrollEmpImg();
            empImg.setPayrollEmpId(payrollEmp.getId());
            empImg.setImgUrl(imgUrl);
            appPayrollEmpImgMapper.insertSelective(empImg);
        }
    }

    @Override
    public void del(Integer payrollId) {
        logger.info("删除工资记录，payrollId：{}", payrollId);
        appPayrollMapper.deleteLogicById(payrollId);
    }

    @Override
    public void commit(Integer payrollId) {
        logger.info("提交工资发放，payrollId：{}", payrollId);
        appPayrollMapper.updateState(payrollId);
    }

    @Override
    public AppPayrollAttachAddDTO attachAdd(String filename, String url, Integer payrollId) {
        logger.info("添加工资发放附件，payrollId：{}，filename：{}，url：{}", payrollId, filename, url);
        AppPayrollAttachAddDTO appPayrollAttachAddDTO = new AppPayrollAttachAddDTO();
        AppPayrollAttach record = new AppPayrollAttach();
        record.setName(filename);
        record.setPayrollId(payrollId);
        record.setUrl(url);
        appPayrollAttachMapper.insertSelective(record);
        appPayrollAttachAddDTO.setUrl(url);
        appPayrollAttachAddDTO.setName(filename);
        appPayrollAttachAddDTO.setAttachId(record.getId());
        return appPayrollAttachAddDTO;
    }

    @Override
    public void attachDel(Integer attachId) {
        logger.info("删除工资附件，attachId：{}", attachId);
        appPayrollAttachMapper.deleteLogicByAttachId(attachId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addList(List<AppPayrollEmpDTO> list, Integer payrollId) throws BizException {
        logger.info("批量添加员工工资，payrollId：{},list:{}", payrollId, list);
        AppPayroll payroll = appPayrollMapper.selectByPrimaryKey(payrollId);
        if (payroll == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "工资发放记录不存在");
        }
        list = list.stream().filter(appPayrollEmpDTO -> {
            String idCardNo = appPayrollEmpDTO.getIdCardNo();
            if (StringUtils.isEmpty(idCardNo)) {
                return false;
            }
            AppEmp appEmp = appEmpMapper.selectByDeptIdAndIdCardNo(payroll.getDeptId(), idCardNo);
            if (appEmp == null) {
                logger.warn("身份证号:{}的人员不存在", idCardNo);
                return false;
            }
            appPayrollEmpDTO.setEmpId(appEmp.getId());
            appPayrollEmpDTO.setPayrollId(payrollId);
            return true;
        }).collect(Collectors.toList());
        if (list.size() > 0) {
            appPayrollEmpMapper.deleteLogicByPayrollId(payrollId);
            appPayrollEmpMapper.batchInsert(list);
        }
    }

    @Override
    public ListData<AppPayrollEmpDTO> getPayrollList(Integer empId) {
        logger.info("根据人员id查找工资发放列表，empId：{}", empId);
        List<AppPayrollEmpDTO> list = appPayrollEmpMapper.selectByEmpId(empId);
        // 查找银行卡信息
        String bankNumber = appEmpBankMapper.selectBankNumberByEmpId(empId);

        //设置工资卡 以及 查找工资图片
        for (AppPayrollEmpDTO appPayrollEmpDTO : list) {
            appPayrollEmpDTO.setBankNumber(bankNumber);
            List<String> imgUrlList = appPayrollEmpImgMapper.selectImgUrlList(appPayrollEmpDTO.getId());
            appPayrollEmpDTO.setImgUrlList(imgUrlList);
        }

        return new ListData<>(list);
    }

    @Override
    public List<EmpSyncDTO> getPayrollList(Integer projectId, Integer groupId, Integer year, Integer month, String keyword) {
        return appPayrollEmpMapper.selectSyncList(projectId, groupId, year, month, keyword);
    }

    @Override
    public AppPayrollSyncDTO getSyncDTO(Integer id) {
        return appPayrollEmpMapper.selectSyncDTO(id);
    }

    @Override
    public OssPathDTO export(Integer payrollId) throws BizException {
        logger.info("导出工资列表，payrollId:{}", payrollId);
        AppPayrollDetailDTO appPayrollDetailDTO = detail(payrollId);
        Integer deptId = appPayrollDetailDTO.getDeptId();
        String deptName = sysDeptService.getDeptNameById(deptId);
        Integer month = appPayrollDetailDTO.getMonth();
        Integer year = appPayrollDetailDTO.getYear();
        List<AppPayrollEmpDTO> empList = appPayrollEmpMapper.selectByPayrollId(payrollId);

        OssPathDTO ossPathDTO = new OssPathDTO();
        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/payrollTemplate" + appPayrollDetailDTO.getClearingForm() + ".xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            //写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            // 表格抬头
            HSSFRow row1 = sheet.getRow(1);
            HSSFCell cell0 = row1.getCell(0);
            cell0.setCellValue(String.format(HEAD, deptName, year, month));

            //填充数据
            int rowIdx = 3;
            for (AppPayrollEmpDTO appPayrollEmpDTO : empList) {
                Integer attendDays = appPayrollEmpDTO.getAttendDays();
                Integer realAttendDays = appPayrollEmpDTO.getRealAttendDays();
                Date date = appPayrollEmpDTO.getDate();

                HSSFRow row = sheet.createRow(rowIdx);
                row.setHeight(Short.parseShort("500"));
                row.createCell(0).setCellValue(appPayrollEmpDTO.getEmpName());
                row.createCell(1).setCellValue(appPayrollDetailDTO.getCorpName());
                row.createCell(2).setCellValue(appPayrollEmpDTO.getIdCardNo());
                row.createCell(3).setCellValue(appPayrollEmpDTO.getWorkRoleName());
                row.createCell(4).setCellValue(appPayrollEmpDTO.getWorkTypeName());
                if (1 == appPayrollDetailDTO.getClearingForm()) {
                    row.createCell(5).setCellValue(attendDays);
                    if (realAttendDays != null) {
                        row.createCell(6).setCellValue(realAttendDays);
                    }
                    if (appPayrollEmpDTO.getUnitPrice() != null) {
                        row.createCell(7).setCellValue(appPayrollEmpDTO.getUnitPrice());
                    }
                    if (appPayrollEmpDTO.getSalaryTotal() != null) {
                        row.createCell(8).setCellValue(appPayrollEmpDTO.getSalaryTotal());
                    }
                    if (appPayrollEmpDTO.getSalaryBorrow() != null) {
                        row.createCell(9).setCellValue(appPayrollEmpDTO.getSalaryBorrow());
                    }
                    if (appPayrollEmpDTO.getSalaryDeduct() != null) {
                        row.createCell(10).setCellValue(appPayrollEmpDTO.getSalaryDeduct());
                    }
                    if (appPayrollEmpDTO.getSalaryShould() != null) {
                        row.createCell(11).setCellValue(appPayrollEmpDTO.getSalaryShould());
                    }
                    if (appPayrollEmpDTO.getSalaryReal() != null) {
                        row.createCell(12).setCellValue(appPayrollEmpDTO.getSalaryReal());
                    }
                    if (date != null) {
                        row.createCell(13).setCellValue(date);
                    }
                    if (appPayrollEmpDTO.getRemark() != null) {
                        row.createCell(17).setCellValue(appPayrollEmpDTO.getRemark());
                    }
                } else {
                    if (appPayrollEmpDTO.getWorkAmount() != null) {
                        row.createCell(5).setCellValue(appPayrollEmpDTO.getWorkAmount());
                    }
                    if (appPayrollEmpDTO.getUnitPrice() != null) {
                        row.createCell(6).setCellValue(appPayrollEmpDTO.getUnitPrice());
                    }
                    if (appPayrollEmpDTO.getSalaryTotal() != null) {
                        row.createCell(7).setCellValue(appPayrollEmpDTO.getSalaryTotal());
                    }
                    if (appPayrollEmpDTO.getSalaryBorrow() != null) {
                        row.createCell(8).setCellValue(appPayrollEmpDTO.getSalaryBorrow());
                    }
                    if (appPayrollEmpDTO.getSalaryDeduct() != null) {
                        row.createCell(9).setCellValue(appPayrollEmpDTO.getSalaryDeduct());
                    }
                    if (appPayrollEmpDTO.getSalaryShould() != null) {
                        row.createCell(10).setCellValue(appPayrollEmpDTO.getSalaryShould());
                    }
                    if (appPayrollEmpDTO.getSalaryReal() != null) {
                        row.createCell(11).setCellValue(appPayrollEmpDTO.getSalaryReal());
                    }
                    if (date != null) {
                        row.createCell(12).setCellValue(date);
                    }
                    if (appPayrollEmpDTO.getRemark() != null) {
                        row.createCell(15).setCellValue(appPayrollEmpDTO.getRemark());
                    }
                }
                rowIdx++;
            }

            //保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            //上传oss
            String name = msFilePathConfig.getFilePath("emp/tmp", String.format(HEAD, deptName, year, month), "xls");
            FileInputStream inputStream = new FileInputStream(tempFile);
            String upload = fileHandler.upload(name, inputStream, FileExpirationRules.oneDay);
            ossPathDTO.setPath(upload);
        } catch (Exception e) {
            logger.error("导出工资列表失败", e);
        }
        return ossPathDTO;
    }
}
